/*
 * This file is part of GuitarMaster.
 * 
 * GuitarMaster is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GuitarMaster is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.paris5.master2.guitarmaster.service;

/**
 *
 * @author Leticia Mahamed, Alice Khammy, mourad nedjahi, Saliou Mamadou Barry
 */
import com.paris5.master2.guitarmaster.bean.EcomBid;
import com.paris5.master2.guitarmaster.bean.EcomComment;
import com.paris5.master2.guitarmaster.bean.EcomProduct;
import com.paris5.master2.guitarmaster.bean.EcomProductType;
import com.paris5.master2.guitarmaster.bean.EcomScore;
import com.paris5.master2.guitarmaster.dao.EcomDao;
import com.paris5.master2.guitarmaster.dao.EcomQuery;
import com.paris5.master2.guitarmaster.entity.Bid;
import com.paris5.master2.guitarmaster.entity.Category;
import com.paris5.master2.guitarmaster.entity.Comment;
import com.paris5.master2.guitarmaster.entity.Product;
import com.paris5.master2.guitarmaster.entity.ProductType;
import com.paris5.master2.guitarmaster.entity.Score;
import com.paris5.master2.guitarmaster.entity.User;
import com.paris5.master2.guitarmaster.exception.EcomException;
import com.paris5.master2.guitarmaster.exception.EcomQueryException;
import com.paris5.master2.guitarmaster.exception.EcomValidationException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.security.PermitAll;
import javax.ejb.EJB;
import javax.ejb.Stateless;

/**
 * @author Leticia Mahamed, Alice Khammy, mourad nedjahi, Saliou Mamadou Barry
 *
 */
@Stateless(mappedName = "product")
@PermitAll
public class ServiceProduct implements ServiceProductRemote {

    @EJB
    private EcomDao dao;

    @Override
    public EcomProduct getProduct(int id) {
        Product p = (Product) dao.find(Product.class, id);
        if (p != null) {
            return p.getEcomProduct();
        }
        return null;
    }

    @Override
    public EcomProductType getProductType(int id) throws EcomQueryException {
        ProductType pt = (ProductType) dao.find(ProductType.class, id);
        if (pt != null) {
            return pt.getEcomProductType();
        }
        return null;
    }

    @Override
    public List<EcomProduct> searchProducts(String txt, int offset, int limit, int order_by, boolean desc) throws EcomValidationException, EcomQueryException {
        
        return searchProducts(txt, offset, limit, order_by, desc, true);
    }
    @Override
    public List<EcomProduct> serchProductsEquals(String txt, int offset, int limit, int order_by, boolean order) throws EcomValidationException, EcomQueryException {
       return searchProducts(txt, offset, limit, order_by,false);
    }
    /**
     * 
     * @param txt
     * @param offset
     * @param limit
     * @param order_by
     * @param desc
     * @param like
     * @return
     * @throws EcomValidationException
     * @throws EcomQueryException 
     */
    private List<EcomProduct> searchProducts(String txt, int offset, int limit, int order_by, boolean desc, boolean like) throws EcomValidationException, EcomQueryException {

        ArrayList<EcomProduct> res = null;

        ArrayList params = new ArrayList();
        List<Object> result;
        if(!like){
            params.add(txt);
            result = dao.execute(EcomQuery.PRODUCT_TYPE_TITLE, params, offset, limit);
        } 
        else {
            params.add("%" + txt.toUpperCase() + "%");
            EcomQuery.SEARCH_PRODUCT.setSelectQuery();
            EcomQuery.SEARCH_PRODUCT.setQueryOrder(order_by, desc);
            result = dao.execute(EcomQuery.SEARCH_PRODUCT, params, offset, limit);
        }
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object r : result) {
                res.add(((Product) r).getEcomProduct());
            }
        }

        return res;
    }
    /**
     * 
     * @param txt
     * @return
     * @throws EcomValidationException
     * @throws EcomQueryException 
     */
    @Override
    public Integer countSearchedProducts(String txt) throws EcomValidationException, EcomQueryException {
        ArrayList params = new ArrayList();
        params.add("%" + txt.toUpperCase() + "%");
        EcomQuery.SEARCH_PRODUCT.setCountQuery();
        Long result = (Long) dao.execute(EcomQuery.SEARCH_PRODUCT, params);
        if (result != null) {
            return result.intValue();
        }

        return 0;
    }

    @Override
    public List<EcomProductType> getProductTypesByCategory(int categId, int offset, int limit, int order_by, boolean desc) throws EcomValidationException, EcomQueryException {

        ArrayList<EcomProductType> res = null;

        ArrayList params = new ArrayList();
        Category categ = new Category();
        categ.setIdCategory(categId);
        params.add(categ);
        EcomQuery.CATEGORY_PRODUCT_TYPE.setSelectQuery();
        EcomQuery.CATEGORY_PRODUCT_TYPE.setQueryOrder(order_by, desc);
        List<Object> result = dao.execute(EcomQuery.CATEGORY_PRODUCT_TYPE, params, offset, limit);
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object ep : result) {
                res.add(((ProductType) ep).getEcomProductType());
            }
        }

        return res;
    }

    @Override
    public Integer countProductTypesByCategory(int categId) throws EcomValidationException, EcomQueryException {
        ArrayList params = new ArrayList();
        Category categ = new Category();
        categ.setIdCategory(categId);
        params.add(categ);
        EcomQuery.CATEGORY_PRODUCT_TYPE.setCountQuery();
        Long res = (Long) dao.execute(EcomQuery.CATEGORY_PRODUCT_TYPE, params);
        if (res != null) {
            return res.intValue();
        }

        return null;
    }

    @Override
    public List<EcomProduct> getProductByCategory(int categId, int offset, int limit, int order_by, boolean desc) throws EcomValidationException, EcomQueryException {

        ArrayList<EcomProduct> res = null;

        ArrayList params = new ArrayList();
        Category categ = new Category();
        categ.setIdCategory(categId);
        params.add(categ);
        EcomQuery.CATEGORY_PRODUCTS.setSelectQuery();
        EcomQuery.CATEGORY_PRODUCTS.setQueryOrder(order_by, desc);
        List<Object> result = dao.execute(EcomQuery.CATEGORY_PRODUCTS, params, offset, limit);
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object ep : result) {
                res.add(((Product) ep).getEcomProduct());
            }
        }

        return res;
    }

    @Override
    public Integer countProductByCategory(int categId) throws EcomValidationException, EcomQueryException {

        ArrayList params = new ArrayList();
        Category categ = new Category();
        categ.setIdCategory(categId);
        params.add(categ);
        EcomQuery.CATEGORY_PRODUCTS.setCountQuery();
        Long res = (Long) dao.execute(EcomQuery.CATEGORY_PRODUCTS, params);
        if (res != null) {
            return res.intValue();
        }

        return null;
    }

    @Override
    public List<EcomBid> getProductBids(int id_product, int offset, int limit) throws EcomQueryException {

        ArrayList<EcomBid> res = null;
        ArrayList params = new ArrayList();
        params.add(id_product);
        params.add(0);
        params.add(new Date());
        EcomQuery.PRODUCT_BIDS.setSelectQuery();
        EcomQuery.PRODUCT_BIDS.setQueryOrder(1, true);
        List<Object> result = dao.execute(EcomQuery.PRODUCT_BIDS, params, offset, limit);
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object ep : result) {
                res.add(((Bid) ep).getEcomBid());
            }
        }

        return res;
    }
    
    @Override
    public List<EcomProduct> getAllProductsInBid(int offset, int limit, int order, boolean desc) throws EcomQueryException {
        ArrayList<EcomProduct> res = null;
        ArrayList params = new ArrayList();
        params.add(0);
        params.add(new Date());
        EcomQuery.PRODUCT_BID_LIST.setSelectQuery();
        EcomQuery.PRODUCT_BID_LIST.setQueryOrder(order, desc);
        List<Object> result = dao.execute(EcomQuery.PRODUCT_BID_LIST, params, offset, limit);
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object ep : result) {
                res.add(((Product) ep).getEcomProduct());
            }
        }
        
        return res;
    }
    
    @Override
    public EcomBid getLastProductPriceInBid(EcomProduct idProduct, int order, boolean desc) throws EcomQueryException {
        EcomBid res = null;
        ArrayList params = new ArrayList();
        Product prd = new Product(idProduct);
        params.add(prd);
        EcomQuery.PRODUCT_BID_LAST_PRICE.setSelectQuery();
        EcomQuery.PRODUCT_BID_LAST_PRICE.setQueryOrder(1, desc);
        Object result = dao.execute(EcomQuery.PRODUCT_BID_LAST_PRICE, params);
        if (result!=null) {
            res = ((Bid) result).getEcomBid();            
        }
        
        return res;
    }
    
    @Override
    public Integer countAllProductsInBid() throws EcomQueryException {
        ArrayList<EcomProduct> res = null;
        ArrayList params = new ArrayList();
        params.add(0);
        params.add(new Date());
        EcomQuery.PRODUCT_BID_LIST.setCountQuery();
        Long result = (Long) dao.execute(EcomQuery.PRODUCT_BID_LIST, params);
        
        return result.intValue();
    }

    @Override
    public EcomScore setProductTypeScore(int id_product_type, boolean increase) throws EcomValidationException {

        ProductType pt = (ProductType) dao.find(ProductType.class, id_product_type);
        if (pt != null) {
            Score score = pt.getScore();
            int vote = score.getVoteCount();
            int value = score.getVoteValue();
            vote++;
            value = increase ? ++value : value;
            score.setVoteCount(vote);
            score.setVoteValue(value);
            pt.setScore(score);
            dao.update(pt);
            return pt.getEcomProductType().getScore();
        } else {
            throw new EcomValidationException("User doesn't exists");
        }
    }

    @Override
    public List<EcomComment> getComments(int id_product_type, int offset, int limit) throws EcomQueryException {
        ArrayList<EcomComment> res = null;
        ArrayList params = new ArrayList();
        ProductType p = new ProductType();
        p.setIdProductType(id_product_type);
        params.add(p);
        EcomQuery.PRODUCTTYPE_COMMENTS.setSelectQuery();
        EcomQuery.PRODUCTTYPE_COMMENTS.setQueryOrder(1, true);
        List<Object> result = dao.execute(EcomQuery.PRODUCTTYPE_COMMENTS, params, offset, limit);
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object ep : result) {
                res.add(((Comment) ep).getEcomComment());
            }
        }

        return res;
    }

    @Override
    public void setComment(int id_user, int id_product_type, String comment) {
        
        User u = new User();
        u.setIdUser(id_user);
        ProductType pt = new ProductType();
        pt.setIdProductType(id_product_type);
        
        Comment com = new Comment();
        com.setDateCreation(new Date());
        com.setDescription(comment);
        com.setIdProductType(pt);
        com.setIdUser(u);
        
        dao.insert(com);
    }

    @Override
    public void bid(int id_user, int id_product, Float price) throws EcomQueryException, EcomException {

        ArrayList params = new ArrayList();
        Date now = new Date();
        params.add(id_product);
        params.add(0);
        params.add(now);

        EcomQuery.PRODUCT_BIDS.setSelectQuery();
        EcomQuery.PRODUCT_BIDS.setQueryOrder(1, true);
        Bid lastBid = (Bid) dao.execute(EcomQuery.PRODUCT_BIDS, params);
        Product p = (Product) dao.find(Product.class, id_product);
        if (p != null && p.getBidEndDate()!=null && p.getBidEndDate().after(now) && ((lastBid != null && lastBid.getBidPrice() <= price) || lastBid == null)) {
            Bid bid = new Bid();
            User u = (User) dao.find(User.class, id_user);
            bid.setIdUser(u);
            bid.setIdProduct(p);
            bid.setDateCrea(now);
            bid.setBidPrice(price);
            dao.insert(bid);
        } else {
            throw new EcomException(p, "Bid ends or price is low");
        }
    }
    
    @Override
    public List<EcomProduct> getAllProduct(int offset, int limit){
        ArrayList<EcomProduct> res = null;
        List<Object> result = dao.findAll(Product.class, offset, limit);
        if(result!=null){
            res = new ArrayList();
            for(Object obj: result){
                Product product = (Product) obj;
                res.add(product.getEcomProduct());
            }
        }
        
        return res;
    }

    @Override
    public Integer countAllProduct() {
        return dao.countAll(Product.class);
    }
    
    @Override
    public List<EcomProductType> getAllProductType(int offset, int limit){
        ArrayList<EcomProductType> res = null;
        List<Object> result = dao.findAll(ProductType.class, 0, limit);
        if(result!=null){
            res = new ArrayList();
            for(Object obj: result){
                ProductType product = (ProductType) obj;
                res.add(product.getEcomProductType());
            }
        }
        
        return res;
    }

    @Override
    public Integer countAllProductType() {
        return dao.countAll(ProductType.class);
    }
    
    @Override
    public int getAvailableQuantity(int idProducType){
         ProductType product = (ProductType) dao.find(ProductType.class, idProducType);
         return product.getQuantity();
    }
    
    @Override
    public void withdrawQuantity(Integer idProductType, Integer quantity) {
        ProductType product = (ProductType) dao.find(ProductType.class, idProductType);
        product.setQuantity(product.getQuantity() - quantity);
        dao.update(product);
    }

    @Override
    public List<EcomProduct> getProductByProductType(int idProductType, int offset, int limit)throws EcomQueryException {
        ArrayList<EcomProduct> res = null;
        ArrayList params = new ArrayList();
        params.add(idProductType);
        EcomQuery.SEACH_PRODUCT_BY_PRODUCT_TYPE.setSelectQuery();
        List<Object> result = dao.execute(EcomQuery.SEACH_PRODUCT_BY_PRODUCT_TYPE, params, offset, limit);
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object r : result) {
                res.add(((Product) r).getEcomProduct());
            }
        }

        return res;
    }

    @Override
    public List<EcomProduct> getProductsPriceLessThan(float price, int offset, int limit) throws EcomValidationException, EcomQueryException {
        ArrayList<EcomProduct> res = null;
        ArrayList params = new ArrayList();
        params.add(price);
        EcomQuery.PRODUCT_PRICE_LESS_THAN.setSelectQuery();
        List<Object> result = dao.execute(EcomQuery.PRODUCT_PRICE_LESS_THAN, params, offset, limit);
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object ep : result) {
                res.add(((Product) ep).getEcomProduct());
            }
        }

        return res;
    }

    @Override
    public Integer countProductsPriceLessThan(float price) throws EcomValidationException, EcomQueryException {
        ArrayList<EcomProduct> res = null;
        ArrayList params = new ArrayList();
        params.add(price);
        EcomQuery.PRODUCT_PRICE_LESS_THAN.setCountQuery();
         Long resultat = (Long)  dao.execute(EcomQuery.PRODUCT_PRICE_LESS_THAN, params);
        if (resultat != null) {
            return resultat.intValue();
        }
        return null;
    }
    
    @Override
    public List<EcomProductType> getProductsPriceBewenn(float lowerPrice, int higherPrice, int offset, int limit) throws EcomValidationException, EcomQueryException {
      ArrayList<EcomProductType> res = null;
        ArrayList params = new ArrayList();
        params.add(lowerPrice);
        params.add(higherPrice);
        EcomQuery.PRODUCT_PRICE_BEWEN.setSelectQuery();
        List<Object> result = dao.execute(EcomQuery.PRODUCT_PRICE_BEWEN, params, offset, limit);
        if (!result.isEmpty()) {
            res = new ArrayList();
            for (Object ep : result) {
                res.add(((ProductType) ep).getEcomProductType());
            }
        }
        
        return res;

    }
}
